package com.mini.grpc.protoc.model;

import java.util.Objects;

/**
 * 方法定义模型
 * 表示一个gRPC方法的完整定义
 * 
 * @author Mini-gRPC
 */
public class MethodDefinition {
    
    /**
     * 方法类型枚举
     */
    public enum MethodType {
        UNARY,              // 一元调用
        CLIENT_STREAMING,   // 客户端流式调用
        SERVER_STREAMING,   // 服务端流式调用
        BIDI_STREAMING      // 双向流式调用
    }
    
    private final String methodName;
    private final String inputType;
    private final String outputType;
    private final MethodType methodType;
    private final boolean clientStreaming;
    private final boolean serverStreaming;
    private final String javaMethodName;
    private final String javaInputType;
    private final String javaOutputType;
    
    /**
     * 构造函数
     * 
     * @param methodName 方法名
     * @param inputType 输入类型
     * @param outputType 输出类型
     * @param clientStreaming 是否客户端流式
     * @param serverStreaming 是否服务端流式
     */
    public MethodDefinition(String methodName,
                          String inputType,
                          String outputType,
                          boolean clientStreaming,
                          boolean serverStreaming) {
        this.methodName = methodName;
        this.inputType = inputType;
        this.outputType = outputType;
        this.clientStreaming = clientStreaming;
        this.serverStreaming = serverStreaming;
        this.methodType = determineMethodType(clientStreaming, serverStreaming);
        this.javaMethodName = toJavaMethodName(methodName);
        this.javaInputType = toJavaTypeName(inputType);
        this.javaOutputType = toJavaTypeName(outputType);
    }
    
    /**
     * 确定方法类型
     * 
     * @param clientStreaming 是否客户端流式
     * @param serverStreaming 是否服务端流式
     * @return 方法类型
     */
    private MethodType determineMethodType(boolean clientStreaming, boolean serverStreaming) {
        if (clientStreaming && serverStreaming) {
            return MethodType.BIDI_STREAMING;
        } else if (clientStreaming) {
            return MethodType.CLIENT_STREAMING;
        } else if (serverStreaming) {
            return MethodType.SERVER_STREAMING;
        } else {
            return MethodType.UNARY;
        }
    }
    
    /**
     * 转换为Java方法名
     * 
     * @param protoMethodName proto方法名
     * @return Java方法名
     */
    private String toJavaMethodName(String protoMethodName) {
        if (protoMethodName == null || protoMethodName.isEmpty()) {
            return protoMethodName;
        }
        
        // 将首字母转为小写
        return Character.toLowerCase(protoMethodName.charAt(0)) + 
               protoMethodName.substring(1);
    }
    
    /**
     * 转换为Java类型名
     * 
     * @param protoTypeName proto类型名
     * @return Java类型名
     */
    private String toJavaTypeName(String protoTypeName) {
        if (protoTypeName == null || protoTypeName.isEmpty()) {
            return protoTypeName;
        }
        
        // 移除包名前缀，只保留类名
        int lastDotIndex = protoTypeName.lastIndexOf('.');
        if (lastDotIndex >= 0) {
            return protoTypeName.substring(lastDotIndex + 1);
        }
        
        return protoTypeName;
    }
    
    /**
     * 获取方法名
     * 
     * @return 方法名
     */
    public String getMethodName() {
        return methodName;
    }
    
    /**
     * 获取输入类型
     * 
     * @return 输入类型
     */
    public String getInputType() {
        return inputType;
    }
    
    /**
     * 获取输出类型
     * 
     * @return 输出类型
     */
    public String getOutputType() {
        return outputType;
    }
    
    /**
     * 获取方法类型
     * 
     * @return 方法类型
     */
    public MethodType getMethodType() {
        return methodType;
    }
    
    /**
     * 是否客户端流式
     * 
     * @return 如果是客户端流式返回true
     */
    public boolean isClientStreaming() {
        return clientStreaming;
    }
    
    /**
     * 是否服务端流式
     * 
     * @return 如果是服务端流式返回true
     */
    public boolean isServerStreaming() {
        return serverStreaming;
    }
    
    /**
     * 获取Java方法名
     * 
     * @return Java方法名
     */
    public String getJavaMethodName() {
        return javaMethodName;
    }
    
    /**
     * 获取Java输入类型
     * 
     * @return Java输入类型
     */
    public String getJavaInputType() {
        return javaInputType;
    }
    
    /**
     * 获取Java输出类型
     * 
     * @return Java输出类型
     */
    public String getJavaOutputType() {
        return javaOutputType;
    }
    
    /**
     * 获取方法描述符字段名
     * 
     * @return 方法描述符字段名
     */
    public String getMethodDescriptorFieldName() {
        return "METHOD_" + methodName.toUpperCase();
    }
    
    /**
     * 获取方法ID
     * 
     * @return 方法ID
     */
    public String getMethodId() {
        return methodName;
    }
    
    /**
     * 是否是一元调用
     * 
     * @return 如果是一元调用返回true
     */
    public boolean isUnary() {
        return methodType == MethodType.UNARY;
    }
    
    /**
     * 是否是流式调用
     * 
     * @return 如果是流式调用返回true
     */
    public boolean isStreaming() {
        return methodType != MethodType.UNARY;
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        MethodDefinition that = (MethodDefinition) obj;
        return clientStreaming == that.clientStreaming &&
               serverStreaming == that.serverStreaming &&
               Objects.equals(methodName, that.methodName) &&
               Objects.equals(inputType, that.inputType) &&
               Objects.equals(outputType, that.outputType) &&
               methodType == that.methodType;
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(methodName, inputType, outputType, 
                          methodType, clientStreaming, serverStreaming);
    }
    
    @Override
    public String toString() {
        return "MethodDefinition{" +
                "methodName='" + methodName + '\'' +
                ", inputType='" + inputType + '\'' +
                ", outputType='" + outputType + '\'' +
                ", methodType=" + methodType +
                ", clientStreaming=" + clientStreaming +
                ", serverStreaming=" + serverStreaming +
                '}';
    }
} 